/**
 * 
 */
package br.ufal.ic.sd.project.logbyk.core;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.Socket;
import java.sql.Timestamp;
import java.util.Properties;

import org.apache.commons.logging.Log;

import br.ufal.ic.sd.project.enumeration.LogType;
import br.ufal.ic.sd.project.exception.LogByKException;

/**
 * @author keven andrade
 *
 */
public class LogByK{
    
    private Channel objChannel;
    
    private String strProjectName;

    private String strClassName;
    
    private LogByK(String strClassName) throws LogByKException{
		
	Properties props = new Properties();
	
	try {
	    props.load(new FileInputStream("logbyk.properties"));
	} catch (FileNotFoundException e) {
	    throw new LogByKException(e.getMessage());
	} catch (IOException e) {
	    throw new LogByKException(e.getMessage());
	}
	
	this.objChannel = new Channel();
	this.objChannel.setIntPort(new Integer(props.getProperty("port")));
	this.objChannel.setStrIP(props.getProperty("ip"));
	
	this.strProjectName = new String(props.getProperty("project_name"));
	this.strClassName = strClassName;
	
    }
    
  //================================== Getters and Setters ===============

    /**
     * @return the objChannel
     */
    public Channel getObjChannel() {
        return objChannel;
    }

    /**
     * @param objChannel the objChannel to set
     */
    private void setObjChannel(Channel objChannel) {
        this.objChannel = objChannel;
    }

    /**
     * @return the strProjectName
     */
    private String getStrProjectName() {
        return strProjectName;
    }

    /**
     * @param strProjectName the strProjectName to set
     */
    private void setStrProjectName(String strProjectName) {
        this.strProjectName = strProjectName;
    }
    
    /**
     * @return the strClassName
     */
    private String getStrClassName() {
        return strClassName;
    }

    /**
     * @param strClassName the strClassName to set
     */
    private void setStrClassName(String strClassName) {
        this.strClassName = strClassName;
    }
    
  //=================================== Methods ===========================
        

    public static LogByK getInstance(String strClassName){
	
	LogByK log = null; 
	
	try {
	    log = new LogByK(strClassName);
	} catch (LogByKException e) {
	    // TODO Auto-generated catch block
	    e.printStackTrace();
	}
	
	return log;
    }
    
    /**
     * sends a fatal log message to log server
     * @param strMessage
     */
    public void fatal(String strMessage){
	
	try {
		
        	this.objChannel.connect();
        	
        	this.objChannel.write("LOG");
        	this.objChannel.getObjOutputStreamOut().flush();
        	this.objChannel.write(this.strProjectName);
        	
        	if(this.objChannel.read().equals("OK")){
        	    
        	    this.objChannel.write(LogType.FATAL.name());
        	    this.objChannel.getObjOutputStreamOut().flush();
        	    this.objChannel.write(new Timestamp(System.currentTimeMillis()).toString());
        	    this.objChannel.getObjOutputStreamOut().flush();
        	    this.objChannel.write(this.objChannel.getObjSocket().getInetAddress().getHostAddress());
        	    this.objChannel.getObjOutputStreamOut().flush();
        	    this.objChannel.write(this.strClassName);
        	    this.objChannel.getObjOutputStreamOut().flush();
        	    this.objChannel.write(strMessage);
        	    
        	    if(this.objChannel.read().equals("DONE")){
        		this.objChannel.closeConnection();
        	    }else{
        		System.err.println("Error transfering data");
        	    }
        	    
        	}else{
        	    System.err.println(this.objChannel.read());
        	}

	
	} catch (IOException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	 }
    }
    
    /**
     * sends an fatal log message to log server from stackTraceElement object
     * @param objStack
     */
    public void fatal(StackTraceElement objStack){
		
	String strMessage = "";
	
	try {
		
    	this.objChannel.connect();
    	
    	this.objChannel.write("LOG");
	this.objChannel.getObjOutputStreamOut().flush();
    	this.objChannel.write(this.strProjectName);
    	
    	if(this.objChannel.read().equals("OK")){
    	    
    	    this.objChannel.write(LogType.FATAL.name());
    	    this.objChannel.getObjOutputStreamOut().flush();
    	    this.objChannel.write(new Timestamp(System.currentTimeMillis()).toString());
    	    this.objChannel.getObjOutputStreamOut().flush();
    	    this.objChannel.write(this.objChannel.getObjSocket().getInetAddress().getHostAddress());
    	    this.objChannel.getObjOutputStreamOut().flush();
    	    this.objChannel.write(this.strClassName);
    	    this.objChannel.getObjOutputStreamOut().flush();
    	    this.objChannel.write(strMessage);
    	    
    	    if(this.objChannel.read().equals("DONE")){
    		this.objChannel.closeConnection();
    	    }else{
    		System.err.println("Error transfering data");
    	    }
    	    
    	}else{
    	    System.err.println(this.objChannel.read());
    	}

	
	} catch (IOException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	 }

	
    }

    
    /**
     * sends an error log message to log server
     * @param strMessage
     */
    public void error(String strMessage){
	
	try {
	
        	this.objChannel.connect();
        	
        	this.objChannel.write("LOG");
        	this.objChannel.getObjOutputStreamOut().flush();
        	this.objChannel.write(this.strProjectName);
        	
        	if(this.objChannel.read().equals("OK")){
        	    
        	    this.objChannel.write(LogType.INFO.name());
        	    this.objChannel.getObjOutputStreamOut().flush();
        	    this.objChannel.write(new Timestamp(System.currentTimeMillis()).toString());
        	    this.objChannel.getObjOutputStreamOut().flush();
        	    this.objChannel.write(this.objChannel.getObjSocket().getInetAddress().getHostAddress());
        	    this.objChannel.getObjOutputStreamOut().flush();
        	    this.objChannel.write(this.strClassName);
        	    this.objChannel.getObjOutputStreamOut().flush();
        	    this.objChannel.write(strMessage);
        	    
        	    if(this.objChannel.read().equals("DONE")){
        		this.objChannel.closeConnection();
        	    }else{
        		System.err.println("Error transfering data");
        	    }
        	    
        	}else{
        	    System.err.println(this.objChannel.read());
        	}

	
	} catch (IOException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	 }
    }
    
    /**
     * sends an error log message to log server from stackTraceElement object
     * @param objStack
     */
    public void error(StackTraceElement[] objStack){
	
	for(StackTraceElement s : objStack){
	    
	    System.out.println(s.getClassName() + " - "+ s.getMethodName()  + " - " + s.getLineNumber());
	}
		
	String strMessage = "";
	
	try {
		
    	this.objChannel.connect();
    	
    	this.objChannel.write("LOG");
	this.objChannel.getObjOutputStreamOut().flush();
    	this.objChannel.write(this.strProjectName);
    	
    	if(this.objChannel.read().equals("OK")){
    	    
    	    this.objChannel.write(LogType.ERROR.name());
    	    this.objChannel.getObjOutputStreamOut().flush();
    	    this.objChannel.write(new Timestamp(System.currentTimeMillis()).toString());
    	    this.objChannel.getObjOutputStreamOut().flush();
    	    this.objChannel.write(this.objChannel.getObjSocket().getInetAddress().getHostAddress());
    	    this.objChannel.getObjOutputStreamOut().flush();
    	    this.objChannel.write(this.strClassName);
    	    this.objChannel.getObjOutputStreamOut().flush();
    	    this.objChannel.write(objStack[1].getMethodName() + " - Line:"+ objStack[1].getLineNumber());
    	    
    	    if(this.objChannel.read().equals("DONE")){
    		this.objChannel.closeConnection();
    	    }else{
    		System.err.println("Error transfering data");
    	    }
    	    
    	}else{
    	    System.err.println(this.objChannel.read());
    	}

	
	} catch (IOException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	 }

	
    }
    
    /**
     * sends an warn log message to log server
     * @param strMessage
     */
    public void warn(String strMessage){
	
	try {
		
        	this.objChannel.connect();
        	
        	this.objChannel.write("LOG");
        	this.objChannel.getObjOutputStreamOut().flush();
        	this.objChannel.write(this.strProjectName);
        	
        	if(this.objChannel.read().equals("OK")){
        	    
        	    this.objChannel.write(LogType.WARN.name());
        	    this.objChannel.getObjOutputStreamOut().flush();
        	    this.objChannel.write(new Timestamp(System.currentTimeMillis()).toString());
        	    this.objChannel.getObjOutputStreamOut().flush();
        	    this.objChannel.write(this.objChannel.getObjSocket().getInetAddress().getHostAddress());
        	    this.objChannel.getObjOutputStreamOut().flush();
        	    this.objChannel.write(this.strClassName);
        	    this.objChannel.getObjOutputStreamOut().flush();
        	    this.objChannel.write(strMessage);
        	    
        	    if(this.objChannel.read().equals("DONE")){
        		this.objChannel.closeConnection();
        	    }else{
        		System.err.println("Error transfering data");
        	    }
        	    
        	}else{
        	    System.err.println(this.objChannel.read());
        	}

	
	} catch (IOException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	 }

    }
    
    /**
     * sends an warn log message to log server from stackTraceElement object
     * @param objStack
     */
    public void warn(StackTraceElement objStack){
	
	
    }
    
    
    /**
     * sends an info log message to log server
     * @param strMessage
     */
    public void info(String strMessage){
	
	try {
		
        	this.objChannel.connect();
        	
        	this.objChannel.write("LOG");
        	this.objChannel.getObjOutputStreamOut().flush();
        	this.objChannel.write(this.strProjectName);
        	
        	if(this.objChannel.read().equals("OK")){
        	    
        	    this.objChannel.write(LogType.INFO.name());
        	    this.objChannel.getObjOutputStreamOut().flush();
        	    this.objChannel.write(new Timestamp(System.currentTimeMillis()).toString());
        	    this.objChannel.getObjOutputStreamOut().flush();
        	    this.objChannel.write(this.objChannel.getObjSocket().getInetAddress().getHostAddress());
        	    this.objChannel.getObjOutputStreamOut().flush();
        	    this.objChannel.write(this.strClassName);
        	    this.objChannel.getObjOutputStreamOut().flush();
        	    this.objChannel.write(strMessage);
        	    this.objChannel.write("DONE");
        	    this.objChannel.getObjOutputStreamOut().flush();
        	    
        	    if(this.objChannel.read().equals("OK")){
        		this.objChannel.closeConnection();
        	    }
        	    
        	}else{
        	    System.err.println(this.objChannel.read());
        	}
    
    	
    	} catch (IOException e) {
    		// TODO Auto-generated catch block
    		e.printStackTrace();
    	 }

    }
    
    /**
     * sends an info log message to log server from stackTraceElement object
     * @param objStack
     */
    public void info(StackTraceElement objStack){
	
	
    }
    
    /**
     * sends a debug log message to log server
     * @param strMessage
     */
    public void debug(String strMessage){
	
	try {
		
        	this.objChannel.connect();
        	
        	this.objChannel.write("LOG");
        	this.objChannel.getObjOutputStreamOut().flush();
        	this.objChannel.write(this.strProjectName);
        	
        	if(this.objChannel.read().equals("OK")){
        	    
        	    this.objChannel.write(LogType.DEBUG.name());
        	    this.objChannel.getObjOutputStreamOut().flush();
        	    this.objChannel.write(new Timestamp(System.currentTimeMillis()).toString());
        	    this.objChannel.getObjOutputStreamOut().flush();
        	    this.objChannel.write(this.objChannel.getObjSocket().getInetAddress().getHostAddress());
        	    this.objChannel.getObjOutputStreamOut().flush();
        	    this.objChannel.write(this.strClassName);
        	    this.objChannel.getObjOutputStreamOut().flush();
        	    this.objChannel.write(strMessage);
        	    
        	    if(this.objChannel.read().equals("DONE")){
        		this.objChannel.closeConnection();
        	    }else{
        		System.err.println("Error transfering data");
        	    }
        	    
        	}else{
        	    System.err.println(this.objChannel.read());
        	}

	
	} catch (IOException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	 }
    }
    
    /**
     * sends an debug log message to log server from stackTraceElement object
     * @param objStack
     */
    public void debug(StackTraceElement objStack){
	
	
    }
    
    /**
     * sends a trace log message to log server
     * @param strMessage
     */
    public void trace(String strMessage){
	
	try {
		
        	this.objChannel.connect();
        	
        	this.objChannel.write("LOG");
        	this.objChannel.getObjOutputStreamOut().flush();
        	this.objChannel.write(this.strProjectName);
        	
        	if(this.objChannel.read().equals("OK")){
        	    
        	    this.objChannel.write(LogType.INFO.name());
        	    this.objChannel.getObjOutputStreamOut().flush();
        	    this.objChannel.write(new Timestamp(System.currentTimeMillis()).toString());
        	    this.objChannel.getObjOutputStreamOut().flush();
        	    this.objChannel.write(this.objChannel.getObjSocket().getInetAddress().getHostAddress());
        	    this.objChannel.getObjOutputStreamOut().flush();
        	    this.objChannel.write(this.strClassName);
        	    this.objChannel.getObjOutputStreamOut().flush();
        	    this.objChannel.write(strMessage);
        	    
        	    if(this.objChannel.read().equals("DONE")){
        		this.objChannel.closeConnection();
        	    }else{
        		System.err.println("Error transfering data");
        	    }
        	    
        	}else{
        	    System.err.println(this.objChannel.read());
        	}
	
	} catch (IOException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}
    }
    
    /**
     * sends an trace log message to log server from stackTraceElement object
     * @param objStack
     */
    public void trace(StackTraceElement objStack){
	
	
    }
}
